package com.itheima.ssm.controller;


import com.itheima.ssm.domain.SysLog;
import com.itheima.ssm.service.ISysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import sun.security.util.SecurityConstants;

import javax.servlet.http.HttpServletRequest;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;

@Component
@Aspect
public class LogAop {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private ISysLogService iSysLogService;

    private Date visitTime;//访问日志记录开始时间
    private Class clazz;//访问的类记录
    private Method method;//访问的方法记录

//    前置通知 : 主要是获取（开始的时间，执行类是哪个，执行方法是哪个）
    @Before("execution(* com.itheima.ssm.controller.*.*(..))")
    public void doBefore(JoinPoint jp) throws NoSuchMethodException {
        visitTime = new Date();//获取当前访问的时间
        clazz = jp.getTarget().getClass();//获取具体访问的类
        String methodName = jp.getSignature().getName();//获取访问的方法名称
        Object[] args = jp.getArgs();//获取访问方法参数
//        获取具体的方法对象和参数
        if (args == null || args.length == 0){
            method = clazz.getMethod(methodName);//因为参数为空，所以获取的是无参数方法
        }else {
            Class[] classArgs = new Class[args.length];//因为args参数是数组，所以要用数组接
            for (int i=0;i<args.length;i++){  //遍历出所以的参数，传给classArgs
             classArgs[i]=args[i].getClass();
            }
            clazz.getMethod(methodName,classArgs);//获取到当前的 类 和 方法加参数
        }
    }

//    后置通知 : 方法执行后会出现的记录
    @After("execution(* com.itheima.ssm.controller.*.*(..))")
    public void doAfter(JoinPoint jp) throws Exception {
//        获取访问时长
        long time = new Date().getTime()-visitTime.getTime();

//        获取Url
        String url="";
        if (clazz != null&&method != null&&clazz != LogAop.class){
//            1.先获取类上的@RequestMapping("/orders")
            RequestMapping clazzAnnotation = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
            if (clazzAnnotation != null){
                String[] classValue = clazzAnnotation.value();
//                2.获取方法上的@RequestMapping("/findAll.do")
                RequestMapping methodAnnotation = method.getAnnotation(RequestMapping.class);
                if (methodAnnotation != null){
                    String[] methodValue = methodAnnotation.value();
                    url = classValue[0]+methodValue[0];

//                  获取访问的IP，getRemoteAddr();
                    String ip = request.getRemoteAddr();

//                  获取当前操作对象
                    SecurityContext context = SecurityContextHolder.getContext();//获取当前登入用户
                    User user = (User) context.getAuthentication().getPrincipal();
                    String username = user.getUsername();

//                  将日志信息全部封装到实体类对象（SysLog）
                    SysLog sysLog = new SysLog();
                    sysLog.setExecutionTime(time);//执行时长
                    sysLog.setIp(ip);
                    sysLog.setMethod("[类名] "+clazz.getName()+"[方法名 ]"+method.getName());
                    sysLog.setUrl(url);
                    sysLog.setUsername(username);
                    sysLog.setVisitTime(visitTime);//开始访问时间

//                  调用Service完成日志插入数据库insert
                    iSysLogService.save(sysLog);
                }
            }
        }
    }
}
